﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;

namespace Common.Extensions
{
    /// <summary>
    /// AutoMapper扩展类
    /// </summary>
    public static class AutoMapperExtension
    {
        private static readonly ConcurrentDictionary<(Type, Type), IMapper> AllMapping =
            new ConcurrentDictionary<(Type, Type), IMapper>();

        /// <summary>
        /// 将源对象映射到目标对象
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="obj">源对象</param>
        /// <returns>转化之后的实体</returns>
        public static T MapTo<T>(this object obj)
        {
            if (obj == null) return default;
            var mapper = GetOrCreateMapper(obj.GetType(), typeof(T));
            return mapper.Map<T>(obj);
        }

        /// <summary>
        /// 将源对象映射到目标对象
        /// </summary>
        /// <typeparam name="T1">源类型</typeparam>
        /// <typeparam name="T2">目标类型</typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static List<T2> MapToList<T1, T2>(this List<T1> obj)
        {
            if (obj == null) return null;
            var result = new List<T2>();
            foreach (var item in obj)
            {
                var temp = item.MapTo<T2>();
                result.Add(temp);
            }

            return result;
        }

        /// <summary>
        /// 将源对象映射到目标对象
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="dto">源对象</param>
        /// <param name="entity">目标对象</param>
        /// <returns>转化之后的实体</returns>
        public static T Map<T>(object dto, T entity)
        {
            var mapper = GetOrCreateMapper(dto.GetType(), typeof(T));
            var newModel = mapper.Map(dto, entity);
            return newModel;
        }


        private static IMapper GetOrCreateMapper(Type sourceType, Type destinationType)
        {
            return AllMapping.GetOrAdd((sourceType, destinationType), key =>
            {
                var config = new MapperConfiguration(cfg => cfg.CreateMap(key.Item1, key.Item2));
                return config.CreateMapper();
            });
        }

        /// <summary>
        ///     设置属性值 原->目标
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="target">目标</param>
        /// <param name="source">原</param>
        /// <param name="excludes">排除赋值的字段</param>
        public static void SetModelValue<T>(this T target, object source, params string[] excludes) where T : class
        {
            var infos = typeof(T).GetProperties();
            foreach (var info in infos)
            {
                if (excludes.FirstOrDefault(x => x == info.Name) != null) continue;
                var proInfo = source.GetType().GetProperty(info.Name);
                if (proInfo != null) info.SetValue(target, proInfo.GetValue(source));
            }
        }
    }
}